﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security.Cryptography;

namespace iPdf
{
    class FileCryptography
    {
        private const int MaxPasswordLength = 8;

        private static string EncryptExtension = ".enc";
        private static string DecryptExtension = ".dec";

        public static string EncryptFile(string inFileName, string password)
        {
            // The following function uses Rijndael encryption algorithm to encrypt file

            // Becouse the Rijndael algoritm is private-key algoritm we need one
            // private key and IV. I composed private key from password entered by user.
            // IV is the same as password but this probably is not good.
            // A key and IV have to be exactly 16 bytes length so we have to truncate
            // password if it is longer then 8 characters (16 bytes) or to add some characters
            // if password length is less then 8 characters.

            try
            {
                if (password.Length > MaxPasswordLength)
                    password = password.Substring(0, MaxPasswordLength);
                else if (password.Length < MaxPasswordLength)
                {
                    int add = MaxPasswordLength - password.Length;
                    for (int i = 0; i < add; i++)
                        password = password + i;
                }
                UnicodeEncoding UE = new UnicodeEncoding();
                byte[] key = UE.GetBytes(password);

                string encryptFileName = Helper.GetTemporaryFile(EncryptExtension);
                FileStream cryptFS = new FileStream(encryptFileName, FileMode.Create);

                RijndaelManaged RMCrypto = new RijndaelManaged();

                CryptoStream cs = new CryptoStream(cryptFS,
                    RMCrypto.CreateEncryptor(key, key),
                    CryptoStreamMode.Write);

                FileStream inFS = new FileStream(inFileName, FileMode.Open);

                int data;
                while ((data = inFS.ReadByte()) != -1)
                    cs.WriteByte((byte)data);

                inFS.Close();
                inFS.Dispose();
                cs.Close();
                cs.Dispose();
                cryptFS.Close();
                cryptFS.Dispose();

                return encryptFileName;
            }
            catch
            {
                return string.Empty;
            }
        }

        public static string DecryptFile(string inFileName, string password)
        {
            try
            {
                if (password.Length > MaxPasswordLength)
                    password = password.Substring(0, MaxPasswordLength);
                else if (password.Length < MaxPasswordLength)
                {
                    int add = MaxPasswordLength - password.Length;
                    for (int i = 0; i < add; i++)
                        password = password + i;
                }

                UnicodeEncoding UE = new UnicodeEncoding();
                byte[] key = UE.GetBytes(password);

                FileStream cryptFS = new FileStream(inFileName, FileMode.Open);

                RijndaelManaged RMCrypto = new RijndaelManaged();

                CryptoStream cs = new CryptoStream(cryptFS,
                    RMCrypto.CreateDecryptor(key, key),
                    CryptoStreamMode.Read);

                string decryptFileName = Helper.GetTemporaryFile(DecryptExtension);
                FileStream outFS = new FileStream(decryptFileName, FileMode.Create);

                int data;
                while ((data = cs.ReadByte()) != -1)
                    outFS.WriteByte((byte)data);

                outFS.Close();
                outFS.Dispose();
                cs.Close();
                cs.Dispose();
                cryptFS.Close();
                cryptFS.Dispose();

                return decryptFileName;
            }
            catch
            {
                return string.Empty;
            }
        }
    }
    
}
